package logic.impl;

import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import util.LevenshteinDistance;

import model.AddressWrapper;
import model.PhoneNumberWrapper;
import model.VCardWrapper;

/**
 * 
 * resolver:
 * 
 * - if country code of phone / fax is missing, try to resolve it using the address
 * - if country of field address is missing, try to resolve it using the country code of phone / fax
 *
 */
public class ResolverCountryCodeFromCountry extends LogicElementBaseClass {
	
	private Properties mappingC2CC;
	private Properties mappingCC2C;
	private int maxLevenshteinDistanceForC2CC;
	
	@Override
	public void init(Properties resolverProperties) {
		super.init(resolverProperties);
		
		mappingC2CC = new Properties();
		mappingCC2C = new Properties();
		maxLevenshteinDistanceForC2CC = 2;

		if(resolverProperties.containsKey("ResolverCountryCodeFromCountry.PathMappingC2CC")) {
			try {
				String path = resolverProperties.getProperty("ResolverCountryCodeFromCountry.PathMappingC2CC");
				log.info("loading mapping C2CC from:" + path);
				mappingC2CC.load(new FileInputStream(new File(path)));
			} catch (Exception exc) {
				log.error(exc);
				
			}
		}
		
		if(resolverProperties.containsKey("ResolverCountryCodeFromCountry.PathMappingCC2C")) {
			try {
				String path = resolverProperties.getProperty("ResolverCountryCodeFromCountry.PathMappingCC2C");
				log.info("loading mapping CC2C from:" + path);
				mappingCC2C.load(new FileInputStream(new File(path)));
			} catch (Exception exc) {
				log.error(exc);
			}
		}		

		if(resolverProperties.containsKey("ResolverCountryCodeFromCountry.MaxLDist_C2CC")) {
			try {
				maxLevenshteinDistanceForC2CC = new Integer(
						resolverProperties.getProperty(
								"ResolverCountryCodeFromCountry.MaxLDist_C2CC"))
				.intValue();
				log.info("set maxLevenshteinDistanceForC2CC to:" + maxLevenshteinDistanceForC2CC);
			} catch (Exception exc) {
				log.error(exc);
			}
		}				
		
	}

	public void performResolving() {

		Vector <VCardWrapper>addressCards = this.getAddressBook().getAddressCards();
		for(int i = 0; i < addressCards.size(); i++) {
			VCardWrapper myCard = addressCards.get(i);
			
			if(myCard.existsAddress() && 
					(myCard.existsPhone() || myCard.existsFax())) {
				
				AddressWrapper address = myCard.getAddress();
				PhoneNumberWrapper phone = null;
				
				if(myCard.existsPhone())
					phone = myCard.getPhone();
				else
					phone = myCard.getFax();
				
				if(address.getCountryName() == null || address.getCountryName().trim().length() == 0) {
					/**
					 * resolve country of address field from phone / fax
					 */
					performResolvingCfromCC(address, phone);
				} else {
					if(phone.existsCountryCode() == false) {
						/**
						 * resolve country code of phone / fax from country of address field
						 */
						performResolvingCCfromC(address, phone);
					}	
				}
			}
			
			if(myCard.existsPhone() && myCard.existsFax()) {
				boolean phoneCCexists = myCard.getPhone().existsCountryCode();
				boolean faxCCexists = myCard.getFax().existsCountryCode();
				
				if(phoneCCexists && faxCCexists == false)
					myCard.getFax().setCountryCode(
							myCard.getPhone().getCountryCode());
				
				if(phoneCCexists == false && faxCCexists)
					myCard.getPhone().setCountryCode(
							myCard.getFax().getCountryCode());
				
			}
		}

		
	}	
	
	/**
	 * 
	 * @param address address to be completed
	 * @param phone number whose cc is used as input for resolving
	 */
	public void performResolvingCfromCC(AddressWrapper address, PhoneNumberWrapper phone) {
				
		String cc = phone.getCountryCode();
		String c = null;
		
		if(mappingCC2C.containsKey(cc)) {
			c = (String) mappingCC2C.getProperty(cc);
			address.setCountryName(c);
			
			log.info("++++++++++ resolved country from countryCode: " + cc + " -> " + c + " ++++++++++");
		}
		
	}
	
	/**
	 * 
	 * @param address address whose country name is used as input for resolving
	 * @param phone number to be completed
	 */
	public void performResolvingCCfromC(AddressWrapper address, PhoneNumberWrapper phone) {
		
		String c = address.getCountryName();
		String cc = null;

		if(mappingC2CC.containsKey(c)) {
			cc = (String) mappingC2CC.getProperty(c);
			phone.setCountryCode(cc);
			
			log.info("++++++++++ resolved countryCode from country: " + c + " -> " + cc + " ++++++++++");
		} else {
			
			/**
			 * country wasn't found in mapping table -> maybe a misspelled country name
			 */
			Iterator countryIter = mappingC2CC.keySet().iterator();
			while(countryIter.hasNext()) {
				
				String cEntry = (String) countryIter.next();
				if(LevenshteinDistance.LD(c, cEntry) <= this.maxLevenshteinDistanceForC2CC) {
					
					/**
					 * levenshtein distance is small enough for a match
					 */
					cc = (String) mappingC2CC.getProperty(cEntry);
					address.setCountryName(cEntry);
					phone.setCountryCode(cc);
			
					log.info("++++++++++ resolved countryCode from country: (" + c + " -> " + cEntry
							+ ") -> " + cc + " ++++++++++");
				}
				
			}
			
		}
		
	}
	
}